package com.example.file

import java.nio.ByteBuffer
import java.nio.ByteOrder
class myBuf {
    var buf = ByteArray(0)
    var dataPos = 0
    var startPos = 0

    internal constructor() {}
    internal constructor(l: Int) {
        buf = ByteArray(l)
    }

    internal constructor(a: ByteArray) {
        buf = a
        dataPos = a.size
    }

    fun get(): ByteArray {
        val r = ByteArray(dataPos - startPos)
        System.arraycopy(buf, startPos, r, 0, dataPos - startPos)
        return r
    }

    fun set(a: ByteArray) {
        buf = a
        startPos = 0
        dataPos = a.size
    }

    fun clear() {
        dataPos = 0
        startPos = dataPos
    }

    fun addLeft(a: ByteArray) {
        if (startPos >= a.size) {
            System.arraycopy(a, 0, buf, startPos - a.size, a.size)
            startPos -= a.size
        } else {
            val tt = get()
            clear()
            append(a)
            append(tt)
        }
    }

    fun size(): Int {
        return dataPos - startPos
    }

    fun append(a: ByteArray) {
        if (a.size + dataPos <= buf.size) {
            System.arraycopy(a, 0, buf, dataPos, a.size)
            dataPos += a.size
            return
        }
        if (a.size + dataPos <= (buf.size * 0.2).toInt()) {
            val r = ByteArray((buf.size * 0.2).toInt())
            System.arraycopy(buf, startPos, r, 0, dataPos - startPos)
            System.arraycopy(a, 0, r, dataPos - startPos, a.size)
            dataPos = dataPos - startPos + a.size
            startPos = 0
            buf = r
            return
        }
        if (a.size + dataPos - startPos <= buf.size) {
            val r = ByteArray(buf.size)
            System.arraycopy(buf, startPos, r, 0, dataPos - startPos)
            System.arraycopy(a, 0, r, dataPos - startPos, a.size)
            dataPos = dataPos - startPos + a.size
            startPos = 0
            buf = r
            return
        }
        var newLe = 2 * buf.size
        if (dataPos - startPos + a.size > newLe) newLe = 2 * a.size
        val r = ByteArray(newLe)
        System.arraycopy(buf, startPos, r, 0, dataPos - startPos)
        System.arraycopy(a, 0, r, dataPos - startPos, a.size)
        dataPos = dataPos - startPos + a.size
        startPos = 0
        buf = r
    }

    fun readArr(l: Int): ByteArray {
        var l = l
        if (l < 0) l = 0
        if (dataPos - startPos < l) l = dataPos - startPos
        val r = ByteArray(l)
        System.arraycopy(buf, startPos, r, 0, l)
        startPos += l
        return r
    }

    fun writeArr(a: ByteArray) {
        append(a)
    }

    fun readQ(): Long {
        val a =
            ByteBuffer.wrap(buf, startPos, 8).order(ByteOrder.nativeOrder())
                .long
        startPos += 8
        return a
    }

    fun writeQ(a: Long) {
        val t =
            ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()).putLong(a)
                .array()
        append(t)
    }

    fun writeFloat(a: Float) {
        val t =
            ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putFloat(a)
                .array()
        append(t)
    }

    fun readFloat(): Float {
        val a =
            ByteBuffer.wrap(buf, startPos, 4).order(ByteOrder.nativeOrder())
                .float
        startPos += 4
        return a
    }

    fun readByte(): Int {
        val b = buf[startPos]
        startPos++
        return if (b < 0) b + 256 else b.toInt()
    }

    fun writeByte(a: Int) {
        val b = a.toByte()
        val xx = ByteArray(1)
        xx[0] = b
        append(xx)
    }

    fun readWord(): Int {
        val a =
            ByteBuffer.wrap(buf, startPos, 2).order(ByteOrder.nativeOrder())
                .short
        startPos += 2
        return if (a < 0) a + 65536 else a.toInt()
    }

    fun writeWord(a: Int) {
        val s = a.toShort()
        val t =
            ByteBuffer.allocate(2).order(ByteOrder.nativeOrder()).putShort(s)
                .array()
        append(t)
    }

    fun readDWord(): Int {
        val a =
            ByteBuffer.wrap(buf, startPos, 4).order(ByteOrder.nativeOrder())
                .int
        startPos += 4
        return a
    }

    fun writeDWord(s: Int) {
        val t =
            ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putInt(s)
                .array()
        append(t)
    }

    fun writeDouble(s: Double) {
        val t =
            ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()).putDouble(s)
                .array()
        append(t)
    }
}